package pl.edu.agh.jemo.evolution.metrics.impl;

import java.math.BigDecimal;
import java.util.List;

import pl.edu.agh.jemo.evolution.metrics.Metric;
import pl.edu.agh.jemo.evolution.population.Population;
import pl.edu.agh.jemo.evolution.specimen.Specimen;

/**
 * 
 * 2D metric
 * 
 */
public class NnmMetric implements Metric {

	private static final String NAME = "Nnm";

	private final List<BigDecimal[]> extrema;
	private final BigDecimal maxDistance;
	private final int minSpecimenCount;

	@Override
	public String getName() {
		return NAME;
	}

	@Override
	public BigDecimal getValue(Population population) {
		BigDecimal result = BigDecimal.ZERO;
		for (final BigDecimal[] extremum : extrema) {
		//	System.out.println("checking extremum [" + extremum[0] + ", " + extremum[1] + "]");
			int specimenCount = 0;
			for (final Specimen specimen : population) {
				final BigDecimal distance = getDistance(extremum[0],
						extremum[1], BigDecimal.valueOf(specimen.getGenotype()
								[0].asDouble()), BigDecimal.valueOf(specimen
								.getGenotype()[1].asDouble()));
				//System.out.println("distance to specimen [" + specimen.getGenotype().get(0)+ ", " + specimen.getGenotype().get(1) + "] is " + distance);
				if (distance.compareTo(maxDistance) <= 0) {
					specimenCount++;
				}
			}
			if (specimenCount >= minSpecimenCount) {
			//	System.out.println("extremum found!");
				result = result.add(BigDecimal.ONE);
			}
		}
	//	System.out.println("total number of extrema found: " + result);
		return result;
	}

	private BigDecimal getDistance(BigDecimal x1, BigDecimal y1, BigDecimal x2,
			BigDecimal y2) {
		BigDecimal firstPart = (x1.subtract(x2)).pow(2);
		final BigDecimal secondPart = (y1.subtract(y2)).pow(2);
		firstPart = firstPart.add(secondPart);
		return BigDecimal.valueOf(Math.sqrt(firstPart.doubleValue()));
	}

	public NnmMetric(List<BigDecimal[]> extrema, BigDecimal maxDistance,
			int minSpecimenCount) {
		this.extrema = extrema;
		this.maxDistance = maxDistance;
		this.minSpecimenCount = minSpecimenCount;
	}
}
